package com.davidlife.jvm.gc.phantomref;

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

/*
使用虚引用跟踪一个可复活对象的回收
 */
public class TraceCanReliveObj {

    public static TraceCanReliveObj obj;

    static ReferenceQueue<TraceCanReliveObj> phantomQueue = null;

    public static class CheckRefQueue extends Thread {
        @Override
        public void run() {
            while (true) {
                if (phantomQueue != null) {
                    PhantomReference<TraceCanReliveObj> obj = null;
                    try {
                        obj = (PhantomReference<TraceCanReliveObj>)phantomQueue.remove();  //阻塞方法
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    /*
                    引用博客中一句话：
                        当大量使用Reference时，虽然Reference指向的对象可能被回收了，但Reference本身也是个对象，
                        所以也需要回收。这时就需要使用ReferenceQueue了。
                     */

                    //Reference(SoftReference，WeakReference，PhantomReference的父类)对象进入ReferenceQueue，说明它的实际对象User被回收了。
                    if (obj != null) {
                        System.out.println("TraceCanReliveObj is delete by GC !");
                    }
                }
            }
        }
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("TraceCanReliveObj finalize Called");
        //在finalize中可复活对象
        obj = this;  //finalize函数是实例方法，因此this也会被传入此方法。
    }

    @Override
    public String toString() {
        return "I am TraceCanReliveObj";
    }

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new CheckRefQueue();
        thread.setDaemon(true);
        thread.start();

        phantomQueue = new ReferenceQueue<>();
        obj = new TraceCanReliveObj();
        PhantomReference<TraceCanReliveObj> phantomRef = new PhantomReference<>(obj, phantomQueue);

        obj = null;
        System.gc();
        Thread.sleep(1000);
        if (obj == null) {
            System.out.println("obj 是 null");
        } else {
            System.out.println("obj 可用");
        }
        System.out.println("第2次 gc");
        obj = null;
        System.gc();
        if (obj == null) {
            System.out.println("obj 是 null");
        } else {
            System.out.println("obj 可用");
        }
    }
}

/*
程序输出为：
TraceCanReliveObj finalize Called
obj 可用
第2次 gc
obj 是 null
TraceCanReliveObj is delete by GC !
 */
